package cn.ren.cloud.service.impl;

import cn.ren.cloud.doc.EsCourseDoc;
import cn.ren.cloud.dto.CourseSearchDto;
import cn.ren.cloud.repository.EsCourseRepository;
import cn.ren.cloud.result.PageList;
import cn.ren.cloud.service.IEsCourseService;
import cn.ren.cloud.utiles.EsPageList;
import cn.ren.cloud.utiles.HighlightResultMapper;
import cn.ren.cloud.vo.CourseAggResultVo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 23508
 */
@Service
public class EsCourseServiceImpl implements IEsCourseService {

    private final EsCourseRepository esCourseRepository;
    private final ElasticsearchRestTemplate elasticsearchRestTemplate;
    private final HighlightResultMapper highlightResultMapper;

    public EsCourseServiceImpl(EsCourseRepository esCourseRepository, ElasticsearchRestTemplate elasticsearchRestTemplate, HighlightResultMapper highlightResultMapper) {
        this.esCourseRepository = esCourseRepository;
        this.elasticsearchRestTemplate = elasticsearchRestTemplate;
        this.highlightResultMapper = highlightResultMapper;
    }

    /**
     * ES添加
     *
     * @param courseEs
     */
    @Override
    public void save(EsCourseDoc courseEs) {
        esCourseRepository.save(courseEs);
    }

    /**
     * 获取分页集合
     *
     * @param doc
     * @return
     */
    @Override
    public PageList<EsCourseDoc> search(CourseSearchDto doc) {
        // 设置构造器
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        // 设置字段条件
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        if (!StringUtils.isEmpty(doc.getKeyword())) {
            queryBuilder.must(QueryBuilders.matchQuery("name", doc.getKeyword().trim()));
        }
        if (!StringUtils.isEmpty(doc.getCourseTypeId())) {
            queryBuilder.filter(QueryBuilders.termQuery("courserTypeId", doc.getCourseTypeId()));
        }
        if (!StringUtils.isEmpty(doc.getGradeName())) {
            queryBuilder.filter(QueryBuilders.termQuery("gradeName", doc.getGradeName()));
        }
        if (!StringUtils.isEmpty(doc.getChargeName())) {
            queryBuilder.filter(QueryBuilders.termQuery("chargeName", doc.getChargeName()));
        }
        // 设置价格区间查询
        if (!StringUtils.isEmpty(doc.getPriceMin())){
            queryBuilder.filter(QueryBuilders.rangeQuery("price").gte(doc.getPriceMin()));
        }

        // 设置价格区间查询
        if (!StringUtils.isEmpty(doc.getPriceMax())){
            queryBuilder.filter(QueryBuilders.rangeQuery("price").lte(doc.getPriceMax()));
        }
        // 添加条件
        nativeSearchQueryBuilder.withQuery(queryBuilder);
        // 设置高亮
        nativeSearchQueryBuilder.withHighlightFields(new HighlightBuilder.Field("name").preTags("<span style='color:red'>").postTags("</span>"));
        // 设置排序
        if (!StringUtils.isEmpty(doc.getSortField()) && !StringUtils.isEmpty(doc.getSortField())) {
            SortOrder sortOrder = "asc".equals(doc.getSortField()) ? SortOrder.ASC : SortOrder.DESC;
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort(doc.getSortField()).order(sortOrder));
        }
        nativeSearchQueryBuilder.withPageable(PageRequest.of(doc.getPage(), doc.getRows()));
        // 给等级和是否收费进行聚合
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("gradeNameTermsAgg").field("gradeName"));
        nativeSearchQueryBuilder.addAggregation(AggregationBuilders.terms("chargeNameTermsAgg").field("chargeName"));
        AggregatedPage<EsCourseDoc> aggregatedPage = elasticsearchRestTemplate.queryForPage(nativeSearchQueryBuilder.build(), EsCourseDoc.class, highlightResultMapper);
        // 得到聚合结果
        Aggregations aggregations = aggregatedPage.getAggregations();
        Map<String, Aggregation> asMap = aggregations.getAsMap();
        Map<String, List<CourseAggResultVo>> map = new HashMap<>();
        asMap.entrySet().forEach(e -> {
            String key = e.getKey();
            List<? extends Terms.Bucket> buckets = ((ParsedStringTerms) e.getValue()).getBuckets();
            List<CourseAggResultVo> aggs = new ArrayList<>();
            buckets.forEach(b -> {
                Object chargeKey = b.getKey();
                long docCount = b.getDocCount();
                CourseAggResultVo courseAggResultVo = new CourseAggResultVo(chargeKey.toString(), docCount);
                aggs.add(courseAggResultVo);
            });
            map.put(key, aggs);
        });
        return new EsPageList(aggregatedPage.getTotalElements(), aggregatedPage.getContent(), map);
    }
}
